﻿using System;
using System.Configuration;
using System.IO;
using System.Text;
using System.Threading;
using System.Web;

public static class Common
{
    public static string ConnStr = ConfigurationManager.ConnectionStrings["db"].ConnectionString;

    public enum ThumbQ { List, Detail, None }

    public static string Convert(this ulong converted, byte radix, out string errMsg)
    {
        char[] rDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
        char[] outDigits = new char[64];

        errMsg = null;

        if (radix > 62)
        {
            errMsg = $"{radix}不是合理的基数";
            return null;
        }
        else if (radix == 0)
            radix = 10;
        else if (radix == 1)
            radix = 16;

        if (converted == 0) return "0";

        int i;
        for (i = 0; i < outDigits.Length && converted > 0; i++)
        {
            outDigits[outDigits.Length - i - 1] = rDigits[converted % radix];
            converted /= radix;
        }

        return new string(outDigits, outDigits.Length - i, i);
    }

    public static ulong? Convert(this string converted, byte radix, out string errMsg, bool skipInvalidChar = false)
    {
        errMsg = null;

        if (radix > 62)
        {
            errMsg = $"{radix}不是合理的基数";
            return null;
        }

        var result = 0UL;

        foreach (char c in converted.ToCharArray())
            if (char.IsDigit(c) && radix > c - '0')
                result = result * radix + (ulong)(c - '0');
            else if (char.IsUpper(c) && radix > 10 + c - 'A')
                result = result * radix + (ulong)(10 + c - 'A');
            else if (char.IsLower(c) && radix > 36 + c - 'a')
                result = result * radix + (ulong)(36 + c - 'a');
            else if (!skipInvalidChar)
            {
                errMsg = $"{converted}中的[{c}]无法理解成{radix}进制数";
                return null;
            }

        return result;
    }

    /// <summary>
    /// 不用预先判断长度的左截取字符串
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    public static string Left(this object obj, int length)
    {
        var str = obj?.ToString() ?? "";
        return str.ToString()[..Math.Min(str.Length, length)];
    }

    /// <summary>
    /// 类似html的text-overflow:ellipsis效果
    /// </summary>
    /// <param name="str"></param>
    /// <param name="max">最大容纳长度</param>
    /// <returns></returns>
    public static string Ellipsis(this string str, int max) => str.Length <= max ? str : str.Left(max - 2) + "...";

    /// <summary>
	/// 保存上传的文件并返回文件网络路径
	/// </summary>
	/// <param name="file"></param>
    /// <param name="dir"></param>
	/// <returns></returns>
	public static string SaveFile(HttpPostedFile file, string dir)
    {
        string filename;
        var attachmentDir = HttpContext.Current.Server.MapPath("/attachment/" + dir);
        Directory.CreateDirectory(attachmentDir);
        file.SaveAs(Path.Combine(attachmentDir, filename = $"{DateTime.Now.Ticks.ToString("x")}.{file.FileName}"));
        return $"/attachment/{dir}/{filename}";
    }

    /// <summary>
    /// 错误日志
    /// </summary>
    /// <param name="id"></param>
    /// <param name="ex"></param>
    public static void LogError(string id, Exception ex)
    {
        var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.txt");
        var now = DateTime.Now;
        var info = new[] { $"id:{id} {now.ToString("m")} {now.ToString("T")}", "msg:" + ex.Message, "stack ↓↓↓↓↓↓↓", ex.StackTrace, "↑↑↑↑↑↑↑↑↑↑↑↑↑" };

        try
        {
            if (!File.Exists(file))
                File.WriteAllLines(file, info, Encoding.UTF8);
            else
                File.AppendAllLines(file, info, Encoding.UTF8);
        }
        catch { }
    }
}

public class SimpleAdvancedLock
{
    object lck = new object();
    volatile int state = 0;

    /// <summary>
    /// 只要没有互斥锁就执行action。若1秒内尝试100次仍有互斥锁则不动作
    /// </summary>
    /// <param name="callback">共享操作</param>
    /// <returns></returns>
    public void EnterShareBlock(Action callback)
    {
        for (int i = 0; i < 100; i++)
            if (state < 0)
                Thread.Sleep(10);
            else
            {
                lock (lck)
                    if (state >= 0)
                        state++;
                    else
                        continue;

                try { callback(); } catch { }
                Interlocked.Decrement(ref state);
                return;
            }
    }

    /// <summary>
    /// 仅当没有任何锁就执行action。若1秒内尝试100次仍有任何锁则不动作
    /// </summary>
    /// <param name="callback">互斥操作</param>
    /// <returns></returns>
    public void EnterMutexBlock(Action callback)
    {
        for (int i = 0; i < 100; i++)
            if (state != 0)
                Thread.Sleep(10);
            else
                lock (lck)
                {
                    if (state == 0)
                        state = -1;
                    else
                        continue;

                    try { callback(); } catch { }
                    state = 0;
                    return;
                }
    }
}

/// <summary>
/// 带有此标签的方法无须登录
/// </summary>
public class NoLogin : Attribute { }